using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading;
using System.Windows.Forms;

using FinlogiK.FxCop.Statistics.Windows.Properties;


namespace FinlogiK.FxCop.Statistics.Windows
{
	internal static class Program
	{
		#region Methods

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		private static int Main(string[] args)
		{
			int result;
			if (args.Length == 0)
			{
				Program.RunWindowsUI();
				result = 0;
			}
			else
			{
				NativeMethods.AttachConsole(NativeMethods.ParentConsoleProcessId);
				result = Program.RunUnattended(args);
			}
			return result;
		}

		[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is the top-level exception handler for the application when run in Windows mode.")]
		private static void RunWindowsUI()
		{
			try
			{
				Program.WireExceptionHandling();

				Application.EnableVisualStyles();
				Application.SetCompatibleTextRenderingDefault(false);

				Application.Run(new MainForm());
			}
			catch (Exception ex)
			{
				Program.HandleException(ex);
			}
		}

		[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "This is the top-level exception handler for the application when run in unattended mode.")]
		private static int RunUnattended(string[] args)
		{
			ResultCode resultCode;

			if (args.Length > 4)
			{
				resultCode = ResultCode.BadArguments;
				Console.Error.WriteLine(Resources.BadCommandLineArguments);
			}
			else
			{
				UnattendedRunParameters parameters = new UnattendedRunParameters(args);
				if (parameters.ProjectName == null)
				{
					resultCode = ResultCode.BadArguments;
					Console.Error.WriteLine(Resources.BadCommandLineArguments);
				}
				else
				{
					try
					{
						StatisticsCollector statisticsCollector = new StatisticsCollector(parameters.ConnectionString, parameters.ProjectName, parameters.ProjectPath, parameters.FxCopCmdPath);
						statisticsCollector.AnalysisOperationStarting += new EventHandler<AnalysisOperationStartingEventArgs>(Program.AnalysisOperationStarting);
						statisticsCollector.CollectStatistics();

						resultCode = ResultCode.Success;
						Console.WriteLine(Resources.StatisticsCollectionCompletedSuccessfully);
					}
					catch (Exception ex)
					{
						resultCode = ResultCode.ExecutionException;
						Console.Error.WriteLine(ex.ToString());
					}
				}
			}

			return (int)resultCode;
		}

		private static void WireExceptionHandling()
		{
			try
			{
				Application.ThreadException += new ThreadExceptionEventHandler(Program.HandleException);
			}
			catch (SecurityException)
			{
				//Unhandled exceptions will be raised to the CLR if the application does not
				//have sufficient permissions to wire up unhandled exception handling.
			}
		}

		internal static void HandleException(Exception ex)
		{
			MessageBoxEx.Show(ex.Message, MessageBoxIcon.Error);
		}

		private static void HandleException(object sender, ThreadExceptionEventArgs e)
		{
			Program.HandleException(e.Exception);
		}

		private static void AnalysisOperationStarting(object sender, AnalysisOperationStartingEventArgs e)
		{
			Console.WriteLine(Resources.ResourceManager.GetString(
				"AnalysisOperation" + e.Operation.ToString(), Resources.Culture));
		}

		#endregion

		#region Nested types

		private enum ResultCode
		{
			Success = 0,
			BadArguments = 1,
			ExecutionException = 2
		}

		private sealed class UnattendedRunParameters
		{
			#region Fields

			private readonly string _projectName;
			private readonly string _connectionString;
			private readonly string _fxCopCmdPath;
			private readonly string _projectPath;

			#endregion

			#region Constructors

			internal UnattendedRunParameters(string[] commandLineParameters)
			{
				this._projectName = UnattendedRunParameters.GetParameterValue(0, commandLineParameters);
				this._connectionString = UnattendedRunParameters.GetParameterValue(1, commandLineParameters) ?? Settings.Default.StatisticsDatabase;
				this._fxCopCmdPath = UnattendedRunParameters.GetParameterValue(2, commandLineParameters);
				this._projectPath = UnattendedRunParameters.GetParameterValue(3, commandLineParameters);
			}

			#endregion

			#region Properties

			internal string ProjectName
			{
				get
				{
					return this._projectName;
				}
			}

			internal string ConnectionString
			{
				get
				{
					return this._connectionString;
				}
			}

			internal string FxCopCmdPath
			{
				get
				{
					return this._fxCopCmdPath;
				}
			}

			internal string ProjectPath
			{
				get
				{
					return this._projectPath;
				}
			}

			#endregion

			#region Methods

			private static string GetParameterValue(int index, string[] parameters)
			{
				string result = null;
				if (parameters.Length >= index + 1)
				{
					result = parameters[index].Trim('"').Trim();
					if (result.Length == 0) result = null;
				}
				return result;
			}

			#endregion
		}

		#endregion
	}
}